//
// message.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef message_HPP
#define message_HPP

#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <vector>
#include <deque>

#include <boost/guid.hpp>

#include <cm/strings.hpp>

#include <cm/client_server/common.hpp>

namespace cm {
	namespace client_server {

	class message
	{
		//
		// AAAA|BBBB|CCCCCCCCCCCCCCCC|DD
		//
		// AAAA				= La lunghezza del body del messaggio	(non so se big endian o little endian)
		// BBBB				= Il numero di sessione in binario		(non so se big endian o little endian)
		// CCCCCCCCCCCCCCCC	= 16 byte dell'identity_id
		// DD				= Lunghezza del identity_name			(non so se big endian o little endian)
		//
	public:
		typedef unsigned long	body_length_t;	// deve essere quattro byte su qualsiasi piattaforma
	public:
		enum { header_body_length_size			= sizeof(body_length_t) };
		enum { header_session_id_size			= session_id_size };
		enum { header_identity_id_size			= 16 };
		enum { header_identity_name_length_size	= str_len_size };
		enum { header_length					= header_body_length_size + header_session_id_size + header_identity_id_size + header_identity_name_length_size };
		enum { max_body_length					= 512 };
	public:
		message()
		{
			memset(header_,0,header_length);
		}
	public:
		const unsigned char* header() const
		{
			return header_;
		}
		unsigned char* header()
		{
			return header_;
		}
	public:
		body_length_t body_length() const
		{
			body_length_t b_l;
			memcpy(&b_l,header_,header_body_length_size);
			return b_l;
		}
		void body_length(body_length_t length)
		{
			body_length_t b_l = length;
			if (b_l > max_body_length)
				b_l = max_body_length;
			memcpy(header_,&b_l,header_body_length_size);
		}
		const char* body() const
		{
			return body_;
		}
		char* body()
		{
			return body_;
		}
	public:
		cm::client_server::session_id session_id() const
		{
			cm::client_server::session_id s_id;
			memcpy(&s_id,&header_[header_body_length_size],header_session_id_size);
			return s_id;
		}
		void session_id(const cm::client_server::session_id& s_id)
		{
			memcpy(&header_[header_body_length_size],&s_id,header_session_id_size);
		}
	public:
		boost::guid identity_id() const
		{
			const unsigned char* start = &header_[header_body_length_size + header_session_id_size];
			const unsigned char* end   = &header_[header_body_length_size + header_session_id_size + header_identity_id_size];
			return boost::guid(start,end);
		}
		void identity_id(const boost::guid& idty_id)
		{
			std::vector<unsigned char> bytes(idty_id.byte_count());
			idty_id.output_bytes(bytes.begin());
			memcpy(&header_[header_body_length_size + header_session_id_size],&bytes[0],idty_id.byte_count());
		}
	public:
		const char* identity_name() const
		{
			return identity_name_;
		}
		char* identity_name()
		{
			return identity_name_;
		}
		str_len identity_name_length() const
		{
			str_len length;
			memcpy(&length,&header_[header_body_length_size + header_session_id_size + header_identity_id_size],header_identity_name_length_size);
			return length;
		}
		void identity_name_length(str_len length)
		{
			memcpy(&header_[header_body_length_size + header_session_id_size + header_identity_id_size],&length,header_identity_name_length_size);
		}
	private:
		unsigned char	header_[header_length];
		char			identity_name_[cm::client_server::identify_name_max_length];
		char			body_[max_body_length];
	};

	typedef std::deque<message> message_queue;
}}

#endif // message_HPP

